﻿/**************************************************************************
创建时间:	2021/9/28 10:18
作	  者:	张存
邮 	  箱:	zhangcunliang@126.com

Copyright (c) zhcun.cn

描	述：串口服务基类,由子类实现过滤器和Command的加载
记	录：
***************************************************************************/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using ZhCun.SerialIO.Filters;

namespace ZhCun.SerialIO
{
    public class SerialServerBase : SerialCore, IBufferReceive
    {
        public SerialServerBase()
        {
            Filters = new List<IReceiveFilter>();
            Commands = new List<ICommand>();
            LoadFilters();
            LoadCommands();
            Filters.ForEach(s => s.OnFilterFinish = ReceiveFilterAction);
        }
        /// <summary>
        /// 过滤器
        /// </summary>
        protected List<IReceiveFilter> Filters { get; }
        /// <summary>
        /// 命令处理器
        /// </summary>
        protected List<ICommand> Commands { get; }
        /// <summary>
        /// 加载过滤器，子类需 Filters.Add
        /// </summary>
        protected virtual void LoadFilters() { }
        /// <summary>
        /// 加载命令处理器
        /// </summary>
        protected virtual void LoadCommands() { }

        #region 程序集 中 加载 Commands实现

        /// <summary>
        /// 加载命令对象，如果已经加载则跳过
        /// </summary>
        protected void LoadCommands(string assemblyName, Func<Type, bool> TypeFilterFunc)
        {
            LoadCommands(assemblyName, TypeFilterFunc, false);
        }
        /// <summary>
        /// 载入命令实现类
        /// </summary>
        /// <param name="isReset">是否从重新载入，false: 如果已经载入则不再加载</param>
        /// <param name="TypeFilterFunc">类型过滤器，可排除某命名空间的Command</param>
        protected void LoadCommands(string assemblyName, Func<Type, bool> TypeFilterFunc, bool isReset)
        {
            if (!isReset && Commands.Count > 0) return;
            if (isReset)
            {
                Commands.Clear();
            }
            Assembly assembly;
            if (string.IsNullOrWhiteSpace(assemblyName))
            {
                assembly = Assembly.GetEntryAssembly();
            }
            else
            {
                assembly = Assembly.Load(assemblyName);
            }
            var types = assembly.GetTypes();
            foreach (var item in types)
            {
                if (item.GetInterface("ICommand", true) != null && !item.IsAbstract && item.IsClass)
                {
                    if (TypeFilterFunc != null && !TypeFilterFunc(item)) continue;
                    var cmdObj = Activator.CreateInstance(item) as ICommand;
                    Commands.Add(cmdObj);
                }
            }
        }
        /// <summary>
        /// 根据Key查找命令对象
        /// </summary>
        protected ICommand GetCommand(int key)
        {
            return Commands?.Find(s => s.Key == key);
        }

        /// <summary>
        /// 根据类型命令对象
        /// </summary>
        protected T GetCommand<T>() where T : class, ICommand, new()
        {
            return Commands?.Find(s => typeof(T) == s.GetType()) as T;
        }

        #endregion

        #region 接收处理缓存（IBufferReceive）

        /// <summary>
        /// 缓存偏移量
        /// </summary>
        public int ReceiveOffset { get; private set; } = 0;
        /// <summary>
        /// 接收缓冲区
        /// </summary>
        public byte[] ReceiveBuffer { get; protected set; } = new byte[1024];
        /// <summary>
        /// 当需要分包或粘包数据时，设置接收缓存
        /// </summary>
        public int SetReceiveBuffer(byte[] data, int offset, int count)
        {
            if (offset < 0 || data.Length < count)
            {
                throw new Exception("set receive buffer error, offset < 0 or count > data length");
            }
            Array.Copy(data, offset, ReceiveBuffer, ReceiveOffset, count);
            ReceiveOffset += count;
            return ReceiveOffset;
        }
        /// <summary>
        /// 判断是否有接收缓存数据，判断偏移量
        /// </summary>
        public bool HasReceiveBuffer()
        {
            return ReceiveOffset > 0;
        }
        /// <summary>
        /// 重置缓存偏移量
        /// </summary>
        public void RestReceiveBuffer()
        {
            ReceiveOffset = 0;
        }

        #endregion
        /// <summary>
        /// 接收到数据后交给过滤器来处理协议
        /// </summary>
        protected override void OnDataReadOver(byte[] data, int offset, int count)
        {
            foreach (var filter in Filters)
            {
                filter.Filter(this, data, offset, count, false, out _);
            }

            base.OnDataReadOver(data, offset, count);
        }
        /// <summary>
        /// 接收数据解析完成后触发
        /// </summary>
        protected virtual void ReceiveFilterAction(PackageInfo package)
        {
            if (Commands == null || Commands.Count == 0) return;

            var cmd = Commands.Find(s => s.Key == package.Key);
            if (cmd != null)
            {
                cmd.Execute(this, package);
            }
        }

        public override void Dispose()
        {
            base.Dispose();

            RestReceiveBuffer();
            for (int i = 0; i < ReceiveBuffer.Length; i++)
            {
                ReceiveBuffer[i] = 0;
            }
        }
    }
}